home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / tree.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  34.3 KB  |  1,486 lines

  1. /* Directory tree browser for the Midnight Commander
  2.    Copyright (C) 1994, 1995 Janne Kukonlehto
  3.    
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2 of the License, or
  7.    (at your option) any later version.
  8.    
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.    This module has been converted to be a widget.
  19.  
  20.    The program load and saves the tree each time the tree widget is
  21.    created and destroyed.  This is required for the future vfs layer,
  22.    it will be possible to have tree views over virtual file systems.
  23.  
  24.    */
  25. #include <config.h>
  26. #include <sys/types.h>
  27. #ifdef HAVE_UNISTD_H
  28. #include <unistd.h>
  29. #endif
  30. #include <fcntl.h>
  31. #include <sys/param.h>
  32. #include <sys/stat.h>
  33. #include <errno.h>
  34. #include <dirent.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>    /* For free() and atoi() */
  37. #include <string.h>
  38. #include "tty.h"
  39. #include "mad.h"
  40. #include "global.h"
  41. #include "util.h"
  42. #include "color.h"
  43. #include "dialog.h"
  44. #include "dir.h"
  45. #include "dlg.h"
  46. #include "widget.h"
  47. #include "panel.h"
  48. #include "mouse.h"
  49. #include "main.h"
  50. #include "file.h"    /* For copy_dir_dir(), move_dir_dir(), erase_dir() */
  51. #include "help.h"
  52. #include "key.h"    /* For mi_getch() */
  53. #include "tree.h"
  54. #include "cmd.h"
  55. #include "../vfs/vfs.h"
  56.  
  57. extern int command_prompt;
  58.  
  59. #define TREE_NORMALC HOT_FOCUSC
  60.  
  61. /* Specifies the display mode: 1d or 2d */
  62. int tree_navigation_flag;
  63.  
  64. /* If this is true, then when browsing the tree the other window will
  65.  * automatically reload it's directory with the contents of the currently
  66.  * selected directory.
  67.  */
  68. int xtree_mode = 0;
  69.  
  70. /* Forwards */
  71. static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par);
  72. #define tcallback (callback_fn) tree_callback
  73.  
  74. /* "$Id: tree.c,v 1.3 1995/02/21 19:07:24 miguel Exp $" */
  75.  
  76. /* Returns number of common characters */
  77. static inline int str_common (char *s1, char *s2)
  78. {
  79.     int result = 0;
  80.  
  81.     while (*s1++ == *s2++)
  82.     result++;
  83.     return result;
  84. }
  85.  
  86. static tree_entry *back_ptr (tree_entry *ptr, int *count)
  87. {
  88.     int i = 0;
  89.  
  90.     while (ptr && ptr->prev && i < *count){
  91.     ptr = ptr->prev;
  92.     i ++;
  93.     }
  94.     *count = i;
  95.     return ptr;
  96. }
  97.  
  98. static tree_entry *forw_ptr (tree_entry *ptr, int *count)
  99. {
  100.     int i = 0;
  101.  
  102.     while (ptr && ptr->next && i < *count){
  103.     ptr = ptr->next;
  104.     i ++;
  105.     }
  106.     *count = i;
  107.     return ptr;
  108. }
  109.  
  110. /* Searches for specified directory */
  111. static tree_entry *whereis (WTree *tree, char *name)
  112. {
  113.     tree_entry *current = tree->tree_first;
  114.     int flag = -1;
  115.  
  116. #if 0
  117.     if (tree->tree_last){
  118.     flag = strcmp (tree->tree_last->name, name);
  119.     if (flag <= 0){
  120.         current = tree->tree_last;
  121.     } else if (tree->selected_ptr){
  122.         flag = strcmp (tree->selected_ptr->name, name);
  123.         if (flag <= 0){
  124.         current = tree->selected_ptr;
  125.         }
  126.     }
  127.     }
  128. #endif
  129.     while (current && flag < 0
  130.        && (flag = strcmp (current->name, name)) < 0)
  131.     current = current->next;
  132.  
  133.     if (flag == 0)
  134.     return current;
  135.     else
  136.     return NULL;
  137. }
  138.  
  139. /* Add a directory to the list of directories */
  140. tree_entry *tree_add_entry (WTree *tree, char *name)
  141. {
  142.     int flag = -1;
  143.     tree_entry *current = tree->tree_first;
  144.     tree_entry *old = NULL;
  145.     tree_entry *new;
  146.     int i, len;
  147.     int submask = 0;
  148.  
  149.     if (!tree)
  150.     return 0;
  151.     
  152.     if (tree->tree_last && tree->tree_last->next)
  153.     abort ();
  154. #if 0
  155.     if (tree->tree_last){
  156.     flag = strcmp (tree->tree_last->name, name);
  157.     if (flag <= 0){
  158.         current = tree->tree_last;
  159.         old = current->prev;
  160.     } else if (tree->selected_ptr){
  161.         flag = strcmp (tree->selected_ptr->name, name);
  162.         if (flag <= 0){
  163.         current = tree->selected_ptr;
  164.         old = current->prev;
  165.         }
  166.     }
  167.     }
  168. #endif
  169.     /* Search for the correct place */
  170.     while (current && flag < 0
  171.        && (flag = strcmp (current->name, name)) < 0){
  172.     old = current;
  173.     current = current->next;
  174.     }
  175.     
  176.     if (flag == 0)
  177.     return current; /* Already in the list */
  178.  
  179.     /* Not in the list -> add it */
  180.     new = xmalloc (sizeof (tree_entry), "tree, tree_entry");
  181.     if (!current){
  182.     /* Append to the end of the list */
  183.     if (!tree->tree_first){
  184.         /* Empty list */
  185.         tree->tree_first = new;
  186.         new->prev = NULL;
  187.     } else {
  188.         old->next = new;
  189.         new->prev = old;
  190.     }
  191.     new->next = NULL;
  192.     tree->tree_last = new;
  193.     } else {
  194.     /* Insert in to the middle of the list */
  195.     new->prev = old;
  196.     if (old){
  197.         /* Yes, in the middle */
  198.         new->next = old->next;
  199.         old->next = new;
  200.     } else {
  201.         /* Nope, in the beginning of the list */
  202.         new->next = tree->tree_first;
  203.         tree->tree_first = new;
  204.     }
  205.     new->next->prev = new;
  206.     }
  207.     /* tree_count++; */
  208.  
  209.     /* Calculate attributes */
  210.     new->name = strdup (name);
  211.     len = strlen (new->name);
  212.     new->sublevel = 0;
  213.     for (i = 0; i < len; i++)
  214.     if (new->name [i] == PATH_SEP){
  215.         new->sublevel++;
  216.         new->subname = new->name + i + 1;
  217.     }
  218.     if (new->next)
  219.     submask = new->next->submask;
  220.     else
  221.     submask = 0;
  222.     submask |= 1 << new->sublevel;
  223.     submask &= (2 << new->sublevel) - 1;
  224.     new->submask = submask;
  225.     new->mark = 0;
  226.  
  227.     /* Correct the submasks of the previous entries */
  228.     current = new->prev;
  229.     while (current && current->sublevel > new->sublevel){
  230.     current->submask |= 1 << new->sublevel;
  231.     current = current->prev;
  232.     }
  233.  
  234.     /* The entry has now been added */
  235.  
  236.     if (new->sublevel > 1){
  237.     /* Let's check if the parent directory is in the tree */
  238.     char *parent = strdup (new->name);
  239.     int i;
  240.  
  241.     for (i = strlen (parent) - 1; i > 1; i--){
  242.         if (parent [i] == PATH_SEP){
  243.         parent [i] = 0;
  244.         tree_add_entry (tree, parent);
  245.         break;
  246.         }
  247.     }
  248.     free (parent);
  249.     }
  250.  
  251.     return new;
  252. }
  253.  
  254. /* Append a directory to the list of directories */
  255. static tree_entry *tree_append_entry (WTree *tree, char *name)
  256. {
  257.     tree_entry *current, *new;
  258.     int i, len;
  259.     int submask = 0;
  260.  
  261.     /* We assume the directory is not yet in the list */
  262.  
  263.     new = xmalloc (sizeof (tree_entry), "tree, tree_entry");
  264.     if (!tree->tree_first){
  265.         /* Empty list */
  266.         tree->tree_first = new;
  267.         new->prev = NULL;
  268.     } else {
  269.         tree->tree_last->next = new;
  270.         new->prev = tree->tree_last;
  271.     }
  272.     new->next = NULL;
  273.     tree->tree_last = new;
  274.  
  275.     /* Calculate attributes */
  276.     new->name = strdup (name);
  277.     len = strlen (new->name);
  278.     new->sublevel = 0;
  279.     for (i = 0; i < len; i++)
  280.     if (new->name [i] == PATH_SEP){
  281.         new->sublevel++;
  282.         new->subname = new->name + i + 1;
  283.     }
  284.     submask = 1 << new->sublevel;
  285.     submask &= (2 << new->sublevel) - 1;
  286.     new->submask = submask;
  287.     new->mark = 0;
  288.  
  289.     /* Correct the submasks of the previous entries */
  290.     current = new->prev;
  291.     while (current && current->sublevel > new->sublevel){
  292.     current->submask |= 1 << new->sublevel;
  293.     current = current->prev;
  294.     }
  295.  
  296.     /* The entry has now been appended */
  297.     return new;
  298. }
  299.  
  300. static void remove_entry (WTree *tree, tree_entry *entry)
  301. {
  302.     tree_entry *current = entry->prev;
  303.     long submask = 0;
  304.  
  305.     if (tree->selected_ptr == entry){
  306.     if (tree->selected_ptr->next)
  307.         tree->selected_ptr = tree->selected_ptr->next;
  308.     else
  309.         tree->selected_ptr = tree->selected_ptr->prev;
  310.     }
  311.  
  312.     /* Correct the submasks of the previous entries */
  313.     if (entry->next)
  314.     submask = entry->next->submask;
  315.     while (current && current->sublevel > entry->sublevel){
  316.     submask |= 1 << current->sublevel;
  317.     submask &= (2 << current->sublevel) - 1;
  318.     current->submask = submask;
  319.     current = current->prev;
  320.     }
  321.  
  322.     /* Unlink the entry from the list */
  323.     if (entry->prev)
  324.     entry->prev->next = entry->next;
  325.     else
  326.     tree->tree_first = entry->next;
  327.     if (entry->next)
  328.     entry->next->prev = entry->prev;
  329.     else
  330.     tree->tree_last = entry->prev;
  331.     /* tree_count--; */
  332.  
  333.     /* Free the memory used by the entry */
  334.     free (entry->name);
  335.     free (entry);
  336. }
  337.  
  338. void tree_remove_entry (WTree *tree, char *name)
  339. {
  340.     tree_entry *current, *base, *old;
  341.     int len, base_sublevel;
  342.  
  343.     /* Miguel Ugly hack */
  344.     if (name [0] == PATH_SEP && name [1] == 0)
  345.     return;
  346.     /* Miguel Ugly hack end */
  347.     
  348.     base = whereis (tree, name);
  349.     if (!base)
  350.     return;    /* Doesn't exist */
  351.     if (tree->check_name [0] == PATH_SEP && tree->check_name [1] == 0)
  352.     base_sublevel = base->sublevel;
  353.     else
  354.     base_sublevel = base->sublevel + 1;
  355.     len = strlen (base->name);
  356.     current = base->next;
  357.     while (current
  358.        && strncmp (current->name, base->name, len) == 0
  359.        && current->sublevel >= base_sublevel){
  360.     old = current;
  361.     current = current->next;
  362.     remove_entry (tree, old);
  363.     }
  364.     remove_entry (tree, base);
  365. }
  366.  
  367. void tree_destroy (WTree *tree)
  368. {
  369.     tree_entry *current, *old;
  370.  
  371.     save_tree (tree);
  372.     current = tree->tree_first;
  373.     while (current){
  374.     old = current;
  375.     current = current->next;
  376.     free (old->name);
  377.     free (old);
  378.     }
  379.     tree->selected_ptr = tree->tree_first = tree->tree_last = NULL;
  380. }
  381.  
  382. /* Mark the subdirectories of the current directory for delete */
  383. void start_tree_check (WTree *tree)
  384. {
  385.     tree_entry *current;
  386.     int len;
  387.  
  388.     if (!tree)
  389.     tree = (WTree *) find_widget_type (current_dlg, tcallback);
  390.     if (!tree)
  391.     return;
  392.     
  393.     /* Search for the start of subdirectories */
  394.     mc_get_current_wd (tree->check_name, MC_MAXPATHLEN);
  395.     tree->check_start = NULL;
  396.     current = whereis (tree, tree->check_name);
  397.     if (!current){
  398.     /* Cwd doesn't exist -> add it */
  399.     current = tree_add_entry (tree, tree->check_name);
  400.     return;
  401.     }
  402.  
  403.     /* Mark old subdirectories for delete */
  404.     /* Here is the bug reported by Michael */
  405.     tree->check_start = current->next;
  406.     len = strlen (tree->check_name);
  407.     if (tree->check_name [0] == PATH_SEP && tree->check_name [1] == 0)
  408.     tree->check_sublevel = current->sublevel;
  409.     else
  410.     tree->check_sublevel = current->sublevel + 1;
  411.  
  412.     current = tree->check_start;
  413.     while (current
  414.        && strncmp (current->name, tree->check_name, len) == 0
  415.        && current->sublevel >= tree->check_sublevel){
  416.     current->mark = 1;
  417.     current = current->next;
  418.     }
  419. }
  420.  
  421. /* This subdirectory exists -> clear deletion mark */
  422. void do_tree_check (WTree *tree, const char *subname)
  423. {
  424.     char *name;
  425.     tree_entry *current, *base;
  426.     int flag = 0, len;
  427.  
  428.     /* Calculate the full name of the subdirectory */
  429.     if (subname [0] == '.' &&
  430.     (subname [1] == 0 || (subname [1] == '.' && subname [2] == 0)))
  431.     return;
  432.     if (tree->check_name [0] == PATH_SEP && tree->check_name [1] == 0)
  433.     name = copy_strings (PATH_SEP_STR, subname, 0);
  434.     else
  435.     name = copy_strings (tree->check_name, PATH_SEP_STR, subname, 0);
  436.  
  437.     /* Search for the subdirectory */
  438.     current = tree->check_start;
  439.     while (current && (flag = strcmp (current->name, name)) < 0)
  440.     current = current->next;
  441.     
  442.     if (flag != 0)
  443.     /* Doesn't exist -> add it */
  444.     current = tree_add_entry (tree, name);
  445.     free (name);
  446.  
  447.     /* Clear the deletion mark from the subdirectory and its children */
  448.     base = current;
  449.     if (base){
  450.     len = strlen (base->name);
  451.     base->mark = 0;
  452.     current = base->next;
  453.     while (current
  454.            && strncmp (current->name, base->name, len) == 0
  455.            && current->sublevel >= tree->check_sublevel){
  456.         current->mark = 0;
  457.         current = current->next;
  458.     }
  459.     }
  460. }
  461.  
  462. /* Tree check searchs a tree widget in the current dialog and
  463.  * if it finds it, it calls do_tree_check on the subname
  464.  */
  465. void tree_check (const char *subname)
  466. {
  467.     WTree *tree;
  468.  
  469.     tree = (WTree *) find_widget_type (current_dlg, tcallback);
  470.     if (!tree)
  471.     return;
  472.     do_tree_check (tree, subname);
  473. }
  474.  
  475.  
  476. /* Delete subdirectories which still have the deletion mark */
  477. void end_tree_check (WTree *tree)
  478. {
  479.     tree_entry *current, *old;
  480.     int len;
  481.  
  482.     if (!tree)
  483.     tree = (WTree *) find_widget_type (current_dlg, tcallback);
  484.     if (!tree)
  485.     return;
  486.     
  487.     /* Check delete marks and delete if found */
  488.     len = strlen (tree->check_name);
  489.  
  490.     current = tree->check_start;
  491.     while (current
  492.        && strncmp (current->name, tree->check_name, len) == 0
  493.        && current->sublevel >= tree->check_sublevel){
  494.     old = current;
  495.     current = current->next;
  496.     if (old->mark)
  497.         remove_entry (tree, old);
  498.     }
  499. }
  500.  
  501. /* Loads the .mc.tree file */
  502. void load_tree (WTree *tree)
  503. {
  504.     char *filename;
  505.     FILE *file;
  506.     char name [MC_MAXPATHLEN], oldname[MC_MAXPATHLEN];
  507.     char *different;
  508.     int len, common;
  509.  
  510.     filename = copy_strings (home_dir, PATH_SEP_STR ".mc.tree", 0);
  511.     file = fopen (filename, "r");
  512.     free (filename);
  513.     if (!file){
  514.     /* No new tree file -> let's try the old file */
  515.     filename = copy_strings (home_dir, PATH_SEP_STR ".mc.tree.", 0);
  516.     file = fopen (filename, "r");
  517.     free (filename);
  518.     }
  519.     
  520.     if (file){
  521.     /* File open -> read contents */
  522.     oldname [0] = 0;
  523.     while (fgets (name, MC_MAXPATHLEN, file)){
  524.         len = strlen (name);
  525.         if (name [len - 1] == '\n'){
  526.         name [--len] = 0;
  527.         }
  528.         if (name [0] != PATH_SEP){
  529.         /* Clear-text decompression */
  530.         char *s = strtok (name, " ");
  531.  
  532.         if (s){
  533.             common = atoi (s);
  534.             different = strtok (NULL, "");
  535.             if (different){
  536.             strcpy (oldname + common, different);
  537.             tree_append_entry (tree, oldname);
  538.             }
  539.         }
  540.         } else {
  541.         tree_append_entry (tree, name);
  542.         strcpy (oldname, name);
  543.         }
  544.     }
  545.     fclose (file);
  546.     }
  547.     if (!tree->tree_first){
  548.     /* Nothing loaded -> let's add some standard directories */
  549.     tree_add_entry (tree, PATH_SEP_STR);
  550.     tree->selected_ptr = tree->tree_first;
  551.     tree_rescan_cmd (tree);
  552.     tree_add_entry (tree, home_dir);
  553.     tree_chdir (tree, home_dir);
  554.     tree_rescan_cmd (tree);
  555.     }
  556. }
  557.  
  558. /* Save the .mc.tree file */
  559. void save_tree (WTree *tree)
  560. {
  561.     tree_entry *current;
  562.     char *filename;
  563.     FILE *file;
  564.     int i, common;
  565.  
  566.     filename = copy_strings (home_dir, PATH_SEP_STR ".mc.tree", 0);
  567.     file = fopen (filename, "w");
  568.     free (filename);
  569.     if (!file){
  570.     fprintf (stderr, "Can't open the .mc.tree file for writing:\n%s\n",
  571.          unix_error_string (errno));
  572.     return;
  573.     }
  574.  
  575.     current = tree->tree_first;
  576.     while (current){
  577.     if (current->prev && (common = str_common (current->prev->name, current->name)) > 2)
  578.         /* Clear-text compression */
  579.         i = fprintf (file, "%d %s\n", common, current->name + common);
  580.     else
  581.         i = fprintf (file, "%s\n", current->name);
  582.     if (i == EOF){
  583.         fprintf (stderr, "Can't write to the .mc.tree file:\n%s\n",
  584.          unix_error_string (errno));
  585.         break;
  586.     }
  587.     current = current->next;
  588.     }
  589.     fclose (file);
  590. }
  591.  
  592. static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
  593. {
  594.     Dlg_head *h = tree->widget.parent;
  595.     int      line;
  596.  
  597.     /* Show mini info */
  598.     if (tree->is_panel){
  599.     if (!show_mini_info)
  600.         return;
  601.     line = tree_lines+2;
  602.     } else
  603.     line = tree_lines+1;
  604.     
  605.     widget_move (&tree->widget, line, 1);
  606.     hline (' ', tree_cols);
  607.     widget_move (&tree->widget, line, 1);
  608.     
  609.     if (tree->searching){
  610.     /* Show search string */
  611.     attrset (TREE_NORMALC);
  612.     attrset (FOCUSC);
  613.     addch (PATH_SEP);
  614.     
  615.     addstr (name_trunc (tree->search_buffer, tree_cols-2));
  616.     addch (' ');
  617.     attrset (FOCUSC);
  618.     } else {
  619.     /* Show full name of selected directory */
  620.     addstr (name_trunc (tree->selected_ptr->name, tree_cols));
  621.     }
  622. }
  623.  
  624. void show_tree (WTree *tree)
  625. {
  626.     Dlg_head *h = tree->widget.parent;
  627.     tree_entry *current;
  628.     int i, j, topsublevel;
  629.     int x, y;
  630.     int tree_lines, tree_cols;
  631.  
  632.     /* Initialize */
  633.     x = y = 0;
  634.     tree_lines = tlines (tree);
  635.     tree_cols  = tree->widget.cols;
  636.  
  637.     attrset (TREE_NORMALC);
  638.     widget_move ((Widget*)tree, y, x);
  639.     if (tree->is_panel){
  640.     tree_cols  -= 2;
  641.     x = y = 1;
  642.     }
  643.  
  644.     if (tree->tree_shown)
  645.     free (tree->tree_shown);
  646.     tree->tree_shown = (tree_entry**)xmalloc (sizeof (tree_entry*)*tree_lines,
  647.                           "tree, show_tree");
  648.     for (i = 0; i < tree_lines; i++)
  649.     tree->tree_shown [i] = NULL;
  650.     if (tree->tree_first)
  651.     topsublevel = tree->tree_first->sublevel;
  652.     else
  653.     topsublevel = 0;
  654.     if (!tree->selected_ptr){
  655.     tree->selected_ptr = tree->tree_first;
  656.     tree->topdiff = 0;
  657.     }
  658.     current = tree->selected_ptr;
  659.     
  660.     /* Calculate the directory which is to be shown on the topmost line */
  661.     if (tree_navigation_flag){
  662.     i = 0;
  663.     while (current->prev && i < tree->topdiff){
  664.         current = current->prev;
  665.         if (current->sublevel < tree->selected_ptr->sublevel){
  666.         if (strncmp (current->name, tree->selected_ptr->name,
  667.                  strlen (current->name)) == 0)
  668.             i++;
  669.         } else if (current->sublevel == tree->selected_ptr->sublevel){
  670.         for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
  671.         if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
  672.             i++;
  673.         } else if (current->sublevel == tree->selected_ptr->sublevel + 1
  674.                && strlen (tree->selected_ptr->name) > 1){
  675.         if (strncmp (current->name, tree->selected_ptr->name,
  676.                  strlen (tree->selected_ptr->name)) == 0)
  677.             i++;
  678.         }
  679.     }
  680.     tree->topdiff = i;
  681.     } else
  682.     current = back_ptr (current, &tree->topdiff);
  683.  
  684.     /* Loop for every line */
  685.     for (i = 0; i < tree_lines; i++){
  686.     /* Move to the beginning of the line */
  687.     widget_move (&tree->widget, y+i, x);
  688.  
  689.     hline (' ', tree_cols);
  690.     widget_move (&tree->widget, y+i, x);
  691.  
  692.     if (!current)
  693.         continue;
  694.     
  695.     tree->tree_shown [i] = current;
  696.     if (current->sublevel == topsublevel){
  697.         /* Top level directory */
  698.         if (tree->active && current == tree->selected_ptr)
  699.         if (!use_colors && !tree->is_panel) set_attr (0, 1);
  700.         else set_attr (1, 0);
  701.         /* Show full name */
  702.         addstr (name_trunc (current->name, tree_cols - 6));
  703.     } else{
  704.         /* Sub level directory */
  705.  
  706.         acs ();
  707.         /* Output branch parts */
  708.         for (j = 0; j < current->sublevel - topsublevel - 1; j++){
  709.         if (tree_cols - 8 - 3 * j < 9)
  710.             break;
  711.         addch (' ');
  712.         if (current->submask & (1 << (j + topsublevel + 1)))
  713.             addch (ACS_VLINE);
  714.         else
  715.             addch (' ');
  716.         addch (' ');
  717.         }
  718.         addch (' '); j++;
  719.         if (!current->next || !(current->next->submask & (1 << current->sublevel)))
  720.         addch (ACS_LLCORNER);
  721.         else
  722.         addch (ACS_LTEE);
  723.         addch (ACS_HLINE);
  724.         noacs ();
  725.         
  726.         if (tree->active && current == tree->selected_ptr)
  727.         /* Selected directory -> change color */
  728.         if (!use_colors && !tree->is_panel) set_attr (0, 1);
  729.         else set_attr (1, 0);
  730.  
  731.         /* Show sub-name */
  732.         addch (' ');
  733.         addstr (name_trunc (current->subname,
  734.                 tree_cols - 2 - 4 - 3 * j));
  735.     }
  736.     addch (' ');
  737.     
  738.     /* Return to normal color */
  739.     attrset (TREE_NORMALC);
  740.  
  741.     /* Calculate the next value for current */
  742.     if (tree_navigation_flag){
  743.         current = current->next;
  744.         while (current){
  745.         if (current->sublevel < tree->selected_ptr->sublevel){
  746.             if (strncmp (current->name, tree->selected_ptr->name,
  747.                  strlen (current->name)) == 0)
  748.             break;
  749.         } else if (current->sublevel == tree->selected_ptr->sublevel){
  750.             for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
  751.             if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
  752.             break;
  753.         } else if (current->sublevel == tree->selected_ptr->sublevel+1
  754.                && strlen (tree->selected_ptr->name) > 1){
  755.             if (strncmp (current->name, tree->selected_ptr->name,
  756.                  strlen (tree->selected_ptr->name)) == 0)
  757.             break;
  758.         }
  759.         current = current->next;
  760.         }
  761.     } else
  762.         current = current->next;
  763.     }
  764.     tree_show_mini_info (tree, tree_lines, tree_cols);
  765. }
  766.  
  767. static void check_focus (WTree *tree)
  768. {
  769.     if (tree->topdiff < 3)
  770.     tree->topdiff = 3;
  771.     else if (tree->topdiff >= tlines (tree) - 3)
  772.     tree->topdiff = tlines (tree) - 3 - 1;
  773. }
  774.  
  775. void tree_move_backward (WTree *tree, int i)
  776. {
  777.     tree_entry *current;
  778.     int j = 0;
  779.     
  780.     if (tree_navigation_flag){
  781.     current = tree->selected_ptr;
  782.     while (j < i && current->prev
  783.            && current->prev->sublevel >= tree->selected_ptr->sublevel){
  784.         current = current->prev;
  785.         if (current->sublevel == tree->selected_ptr->sublevel){
  786.         tree->selected_ptr = current;
  787.         j ++;
  788.         }
  789.     }
  790.     i = j;
  791.     } else
  792.     tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
  793.     tree->topdiff -= i;
  794.     check_focus (tree);
  795. }
  796.  
  797. void tree_move_forward (WTree *tree, int i)
  798. {
  799.     tree_entry *current;
  800.     int j = 0;
  801.  
  802.     if (tree_navigation_flag){
  803.     current = tree->selected_ptr;
  804.     while (j < i && current->next
  805.            && current->next->sublevel >= tree->selected_ptr->sublevel){
  806.         current = current->next;
  807.         if (current->sublevel == tree->selected_ptr->sublevel){
  808.         tree->selected_ptr = current;
  809.         j ++;
  810.         }
  811.     }
  812.     i = j;
  813.     } else
  814.     tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
  815.     tree->topdiff += i;
  816.     check_focus (tree);
  817. }
  818.  
  819. void tree_move_to_child (WTree *tree)
  820. {
  821.     tree_entry *current;
  822.  
  823.     /* Do we have a starting point? */
  824.     if (!tree->selected_ptr)
  825.     return;
  826.     /* Take the next entry */
  827.     current = tree->selected_ptr->next;
  828.     /* Is it the child of the selected entry */
  829.     if (current && current->sublevel > tree->selected_ptr->sublevel){
  830.     /* Yes -> select this entry */
  831.     tree->selected_ptr = current;
  832.     tree->topdiff++;
  833.     check_focus (tree);
  834.     } else {
  835.     /* No -> rescan and try again */
  836.     tree_rescan_cmd (tree);
  837.     current = tree->selected_ptr->next;
  838.     if (current && current->sublevel > tree->selected_ptr->sublevel){
  839.         tree->selected_ptr = current;
  840.         tree->topdiff++;
  841.         check_focus (tree);
  842.     }
  843.     }
  844. }
  845.  
  846. int tree_move_to_parent (WTree *tree)
  847. {
  848.     tree_entry *current;
  849.     tree_entry *old;
  850.     
  851.     if (!tree->selected_ptr)
  852.     return 0;
  853.     old = tree->selected_ptr;
  854.     current = tree->selected_ptr->prev;
  855.     while (current && current->sublevel >= tree->selected_ptr->sublevel){
  856.     current = current->prev;
  857.     tree->topdiff--;
  858.     }
  859.     if (!current)
  860.     current = tree->tree_first;
  861.     tree->selected_ptr = current;
  862.     check_focus (tree);
  863.     return tree->selected_ptr != old;
  864. }
  865.  
  866. void tree_move_to_top (WTree *tree)
  867. {
  868.     tree->selected_ptr = tree->tree_first;
  869.     tree->topdiff = 0;
  870. }
  871.  
  872. void tree_move_to_bottom (WTree *tree)
  873. {
  874.     tree->selected_ptr = tree->tree_last;
  875.     tree->topdiff = tlines (tree) - 3 - 1;
  876. }
  877.  
  878. void tree_chdir (WTree *tree, char *dir)
  879. {
  880.     tree_entry *current;
  881.  
  882.     current = whereis (tree, dir);
  883.     if (current){
  884.     tree->selected_ptr = current;
  885.     check_focus (tree);
  886.     }
  887. }
  888.  
  889. /* Handle mouse click */
  890. void tree_event (WTree *tree, int y)
  891. {
  892.     if (tree->tree_shown [y]){
  893.     tree->selected_ptr = tree->tree_shown [y];
  894.     tree->topdiff = y;
  895.     }
  896.     show_tree (tree);
  897. }
  898.  
  899. static void chdir_sel (WTree *tree);
  900.  
  901. static maybe_chdir (WTree *tree)
  902. {
  903.     if (!(xtree_mode && tree->is_panel))
  904.     return;
  905.     if (is_idle ())
  906.     chdir_sel (tree);
  907. }
  908.  
  909. /* Mouse callback */
  910. static int event_callback (Gpm_Event *event, WTree *tree)
  911. {
  912.     if (!(event->type & GPM_UP))
  913.     return MOU_ENDLOOP;
  914.  
  915.     if (tree->is_panel)
  916.     event->y--;
  917.     
  918.     event->y--;
  919.  
  920.     if (!tree->active)
  921.     change_panel ();
  922.  
  923.     if (event->y < 0){
  924.     tree_move_backward (tree, tlines (tree) - 1);
  925.     show_tree (tree);
  926.     }
  927.     else if (event->y >= tlines (tree)){
  928.     tree_move_forward (tree, tlines (tree) - 1);
  929.     show_tree (tree);
  930.     } else {
  931.     tree_event (tree, event->y);
  932.     if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
  933.         chdir_sel (tree);
  934.     }
  935.     }
  936.     return MOU_ENDLOOP;
  937. }
  938.  
  939. /* Search tree for text */
  940. int search_tree (WTree *tree, char *text)
  941. {
  942.     tree_entry *current;
  943.     int len;
  944.     int wrapped = 0;
  945.     int found = 0;
  946.  
  947.     len = strlen (text);
  948.     current = tree->selected_ptr;
  949.     found = 0;
  950.     while (!wrapped || current != tree->selected_ptr){
  951.     if (strncmp (current->subname, text, len) == 0){
  952.         tree->selected_ptr = current;
  953.         found = 1;
  954.         break;
  955.     }
  956.     current = current->next;
  957.     if (!current){
  958.         current = tree->tree_first;
  959.         wrapped = 1;
  960.     }
  961.     tree->topdiff++;
  962.     }
  963.     check_focus (tree);
  964.     return found;
  965. }
  966.  
  967. static void tree_do_search (WTree *tree, int key)
  968. {
  969.     int l;
  970.  
  971.     l = strlen (tree->search_buffer);
  972.     if (l && (key == 8 || key == 0177 || key == KEY_BACKSPACE))
  973.     tree->search_buffer [--l] = 0;
  974.     else {
  975.     if (key && l < sizeof (tree->search_buffer)){
  976.         tree->search_buffer [l] = key;
  977.         tree->search_buffer [l+1] = 0;
  978.         l++;
  979.     }
  980.     }
  981.  
  982.     if (!search_tree (tree, tree->search_buffer))
  983.     tree->search_buffer [--l] = 0;
  984.     
  985.     show_tree (tree);
  986.     maybe_chdir (tree);
  987. }
  988.  
  989. int tree_rescan_cmd (WTree *tree)
  990. {
  991.     DIR *dirp;
  992.     struct dirent *dp;
  993.     struct stat buf;
  994.     char old_dir [MC_MAXPATHLEN];
  995.  
  996.     if (!tree->selected_ptr)
  997.     return 0;
  998.     if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
  999.     return 0;
  1000.     if (chdir (tree->selected_ptr->name))
  1001.     return 0;
  1002.     
  1003.     start_tree_check (tree);
  1004.     dirp = opendir (".");
  1005.     if (dirp){
  1006.     for (dp = readdir (dirp); dp; dp = readdir (dirp)){
  1007.         lstat (dp->d_name, &buf);
  1008.         if (S_ISDIR (buf.st_mode))
  1009.         do_tree_check (tree, dp->d_name);
  1010.     }
  1011.     closedir (dirp);
  1012.     }
  1013.     end_tree_check (tree);
  1014.     chdir (old_dir);
  1015.     return 1;
  1016. }
  1017.  
  1018. int tree_forget_cmd (WTree *tree)
  1019. {
  1020.     if (tree->selected_ptr)
  1021.     tree_remove_entry (tree, tree->selected_ptr->name);
  1022.     return 1;
  1023. }
  1024.  
  1025. #if 0
  1026. static int toggle_nav_mode (void)
  1027. {
  1028.     tree_navigation_flag = 1 - tree_navigation_flag;
  1029.  
  1030.     return 1;
  1031. }
  1032. #endif
  1033.  
  1034. void tree_copy (WTree *tree, char *default_dest)
  1035. {
  1036.     char *dest;
  1037.  
  1038.     if (!tree->selected_ptr)
  1039.     return;
  1040.     sprintf (cmd_buf, "Copy \"%s\" directory to:",
  1041.          name_trunc (tree->selected_ptr->name, 60));
  1042.     dest = input_expand_dialog (" Copy ", cmd_buf, default_dest);
  1043.     if (!dest || !*dest){
  1044.     return;
  1045.     }
  1046.     create_op_win (OP_COPY);
  1047.     copy_dir_dir (tree->selected_ptr->name, dest, 1, 0);
  1048.     destroy_op_win ();
  1049.     free (dest);
  1050. }
  1051.  
  1052. static void tree_help_cmd (void)
  1053. {
  1054.     interactive_display (LIBDIR "mc.hlp", "[Directory Tree]");
  1055. }
  1056.  
  1057. static int tree_copy_cmd (WTree *tree)
  1058. {
  1059.     tree_copy (tree, "");
  1060.     return 1;
  1061. }
  1062.  
  1063. void tree_move (WTree *tree, char *default_dest)
  1064. {
  1065.     char *dest;
  1066.     struct stat buf;
  1067.  
  1068.     if (!tree->selected_ptr)
  1069.     return;
  1070.     sprintf (cmd_buf, "Move \"%s\" directory to:",
  1071.          name_trunc (tree->selected_ptr->name, 60));
  1072.     dest = input_expand_dialog (" Move ", cmd_buf, default_dest);
  1073.     if (!dest || !*dest){
  1074.     return;
  1075.     }
  1076.     if (stat (dest, &buf)){
  1077.     message (1, " Error ", " Can't stat the destination \n %s ",
  1078.          unix_error_string (errno));
  1079.     free (dest);
  1080.     return;
  1081.     }
  1082.     if (!S_ISDIR (buf.st_mode)){
  1083.     message (1, " Error ", " The destination isn't a directory ");
  1084.     free (dest);
  1085.     return;
  1086.     }
  1087.     create_op_win (OP_MOVE);
  1088.     move_dir_dir (tree->selected_ptr->name, dest);
  1089.     destroy_op_win ();
  1090.     free (dest);
  1091. }
  1092.  
  1093. static int tree_move_cmd (WTree *tree)
  1094. {
  1095.     tree_move (tree, "");
  1096.     return 1;
  1097. }
  1098.  
  1099. static int tree_mkdir_cmd (WTree *tree)
  1100. {
  1101.     char old_dir [MC_MAXPATHLEN];
  1102.  
  1103.     if (!tree->selected_ptr)
  1104.     return 0;
  1105.     if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
  1106.     return 0;
  1107.     if (chdir (tree->selected_ptr->name))
  1108.     return 0;
  1109.     /* FIXME
  1110.     mkdir_cmd (tree);
  1111.     */
  1112.     tree_rescan_cmd (tree);
  1113.     chdir (old_dir);
  1114.     return 1;
  1115. }
  1116.  
  1117. static int tree_rmdir_cmd (WTree *tree)
  1118. {
  1119.     char old_dir [MC_MAXPATHLEN];
  1120.  
  1121.     if (tree->selected_ptr){
  1122.     if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
  1123.         return 0;
  1124.     if (chdir (PATH_SEP_STR))
  1125.         return 0;
  1126.     if (confirm_delete){
  1127.         char *cmd_buf;
  1128.         int result;
  1129.  
  1130.         cmd_buf = xmalloc (strlen (tree->selected_ptr->name) + 20,
  1131.                    "tree, rmdir_cmd");
  1132.         sprintf (cmd_buf, "  Delete %s?  ", tree->selected_ptr->name);
  1133.         result = query_dialog (" Delete ", cmd_buf, 3, 2, " Yes ", " No ");
  1134.         free (cmd_buf);
  1135.         if (result != 0){
  1136.         return 0;
  1137.         }
  1138.     }
  1139.     create_op_win (OP_DELETE);
  1140.     if (erase_dir (tree->selected_ptr->name) == FILE_CONT)
  1141.         tree_forget_cmd (tree);
  1142.     destroy_op_win ();
  1143.     chdir (old_dir);
  1144.     return 1;
  1145.     } else
  1146.     return 0;
  1147. }
  1148.  
  1149. #if 0
  1150. static int tree_quit_cmd (void)
  1151. {
  1152.     /*
  1153.        FIXME
  1154.     return done = 1;
  1155.     */
  1156.     return 1;
  1157. }
  1158. #endif
  1159.  
  1160. static void set_navig_label (Dlg_head *h);
  1161. static void tree_toggle_navig (Dlg_head *h)
  1162. {
  1163.     tree_navigation_flag = 1 - tree_navigation_flag;
  1164.     set_navig_label (h);
  1165. }
  1166.  
  1167. void set_navig_label (Dlg_head *h)
  1168. {
  1169.     define_label_data (h, (Widget *) NULL,
  1170.         4, tree_navigation_flag ? "Static" : "Dynamc",
  1171.     (void (*)(void *))tree_toggle_navig, h);
  1172. }
  1173.  
  1174. static void move_down (WTree *tree)
  1175. {
  1176.     tree_move_forward (tree, 1);
  1177.     show_tree (tree);
  1178.     maybe_chdir (tree);
  1179. }
  1180.  
  1181. static void move_up (WTree *tree)
  1182. {
  1183.     tree_move_backward (tree, 1);
  1184.     show_tree (tree);
  1185.     maybe_chdir (tree);
  1186. }
  1187.  
  1188. static void move_home (WTree *tree)
  1189. {
  1190.     tree_move_to_top (tree);
  1191.     show_tree (tree);
  1192.     maybe_chdir (tree);
  1193. }
  1194.  
  1195. static void move_end (WTree *tree)
  1196. {
  1197.     tree_move_to_bottom (tree);
  1198.     show_tree (tree);
  1199.     maybe_chdir (tree);
  1200. }
  1201.  
  1202. static int move_left (WTree *tree)
  1203. {
  1204.     int v;
  1205.     
  1206.     if (tree_navigation_flag){
  1207.     v = tree_move_to_parent (tree);
  1208.     show_tree (tree);
  1209.     maybe_chdir (tree);
  1210.     return v;
  1211.     }
  1212.     return 0;
  1213. }
  1214.  
  1215. static int move_right (WTree *tree)
  1216. {
  1217.     if (tree_navigation_flag){
  1218.     tree_move_to_child (tree);
  1219.     show_tree (tree);
  1220.     maybe_chdir (tree);
  1221.     return 1;
  1222.     }
  1223.     return 0;
  1224. }
  1225.  
  1226. static void move_prevp (WTree *tree)
  1227. {
  1228.     tree_move_backward (tree, tlines (tree) - 1);
  1229.     show_tree (tree);
  1230.     maybe_chdir (tree);
  1231. }
  1232.  
  1233. static void move_nextp (WTree *tree)
  1234. {
  1235.     tree_move_forward (tree, tlines (tree) - 1);
  1236.     show_tree (tree);
  1237.     maybe_chdir (tree);
  1238. }
  1239.  
  1240. static void chdir_sel (WTree *tree)
  1241. {
  1242.     if (!tree->is_panel){
  1243.     tree->done = 1;
  1244.     return;
  1245.     }
  1246.     change_panel ();
  1247.     if (do_cd (tree->selected_ptr->name)){
  1248.     paint_panel (cpanel);
  1249.     select_item (cpanel);
  1250.     } else {
  1251.     message (1, " Error ", " Can't chdir to \"%s\" \n %s ",
  1252.          tree->selected_ptr->name, unix_error_string (errno));
  1253.     }
  1254.     change_panel ();
  1255.     show_tree (tree);
  1256.     return;
  1257. }
  1258.  
  1259. static void start_search (WTree *tree)
  1260. {
  1261.     tree->searching = 1;
  1262. }
  1263.  
  1264. static key_map tree_keymap [] = {
  1265.     { XCTRL('n'), move_down    },
  1266.     { XCTRL('p'), move_up      },
  1267.     { KEY_DOWN,   move_down    },
  1268.     { KEY_UP,     move_up      },
  1269.     { '\n',       chdir_sel    },
  1270.     { KEY_ENTER,  chdir_sel    },
  1271.     { KEY_HOME,   move_home    },
  1272.     { KEY_C1,     move_end     },
  1273.     { KEY_END,    move_end     },
  1274.     { KEY_A1,     move_home    },
  1275.     { KEY_NPAGE,  move_nextp   },
  1276.     { KEY_PPAGE,  move_prevp   },
  1277.     { XCTRL('v'), move_nextp   },
  1278.     { ALT('v'),   move_prevp   },
  1279.     { XCTRL('p'), move_up      },
  1280.     { XCTRL('p'), move_down    },
  1281.     { XCTRL('s'), start_search },
  1282.     { ALT('s'),   start_search },
  1283.     };
  1284.  
  1285. static inline int tree_key (WTree *tree, int key)
  1286. {
  1287.     int i;
  1288.  
  1289.     for (i = 0; tree_keymap [i].key_code; i++){
  1290.     if (key == tree_keymap [i].key_code){
  1291.         tree->search_buffer [0] = 0;
  1292.         (*tree_keymap [i].fn)(tree);
  1293.         show_tree (tree);
  1294.         break;
  1295.     }
  1296.     }
  1297.     /* We do not want to use them if we do not need to */
  1298.     /* Input line may want to take the motion key event */
  1299.     if (key == KEY_LEFT)
  1300.     return move_left (tree);
  1301.  
  1302.     if (key == KEY_RIGHT)
  1303.     move_right (tree);
  1304.  
  1305.     if (tree->searching){
  1306.     tree_do_search (tree, key);
  1307.     return 1;
  1308.     }
  1309.     if (!command_prompt)
  1310.     start_search (tree);
  1311.  
  1312.     if (key == -1)
  1313.     return 0;
  1314.     
  1315.     if (tree_keymap [i].key_code == 0){
  1316.     if (tree->search_buffer [0])
  1317.         tree->search_buffer [0] = 0;
  1318.     show_tree (tree);
  1319.     }
  1320.     return  (key > ' ') ? tree->is_panel : 0;
  1321. }
  1322.  
  1323. static void tree_frame (Dlg_head *h, WTree *tree)
  1324. {
  1325.     set_attr (0, 0);
  1326.     widget_erase ((Widget*) tree);
  1327.     if (tree->is_panel)
  1328.     draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
  1329.                  tree->widget.cols);
  1330.     
  1331.     if (show_mini_info && tree->is_panel){
  1332.     widget_move (tree, tlines (tree) + 1, 1);
  1333.     hline (ACS_HLINE, tree->widget.cols - 2);
  1334.     }
  1335. }
  1336.  
  1337.  
  1338. static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par)
  1339. {
  1340.     switch (msg){
  1341.     case WIDGET_DRAW:
  1342.     tree_frame (h, tree);
  1343.     show_tree (tree);
  1344.     return 1;
  1345.  
  1346.     case WIDGET_KEY:
  1347.     return tree_key (tree, par);
  1348.  
  1349.     case WIDGET_FOCUS:
  1350.     tree->active = 1;
  1351.     define_label (h, (Widget *)tree, 1, "Help", (voidfn) tree_help_cmd);
  1352.     define_label_data (h, (Widget *)tree, 
  1353.         2, "Rescan", (buttonbarfn)tree_rescan_cmd, tree);
  1354.     define_label_data (h, (Widget *)tree, 
  1355.         3, "Forget", (buttonbarfn)tree_forget_cmd, tree);
  1356.     define_label_data (h, (Widget *)tree, 
  1357.         5, "Copy",   (buttonbarfn) tree_copy_cmd, tree);
  1358.     define_label_data (h, (Widget *)tree, 
  1359.         6, "RenMov", (buttonbarfn) tree_move_cmd, tree);
  1360.     define_label_data (h, (Widget *)tree, 
  1361.         7, "Mkdir",  (buttonbarfn) tree_mkdir_cmd, tree);
  1362.     define_label_data (h, (Widget *)tree, 
  1363.         8, "Rmdir",  (buttonbarfn) tree_rmdir_cmd, tree);
  1364.     set_navig_label (h);
  1365.     redraw_labels (h, (Widget *)tree);
  1366.  
  1367.     
  1368.     /* FIXME: Should find a better way of only displaying the
  1369.        currently selected item */ 
  1370.     show_tree (tree);
  1371.     return 1;
  1372.  
  1373.     /* FIXME: Should find a better way of changing the color of the
  1374.        selected item */
  1375.     case WIDGET_UNFOCUS:
  1376.     tree->active = 0;
  1377.     show_tree (tree);
  1378.     return 1;
  1379.     }
  1380.     return default_proc (h, msg, par);
  1381. }
  1382.  
  1383. WTree *tree_new (int is_panel, int y, int x, int lines, int cols)
  1384. {
  1385.     WTree *tree = xmalloc (sizeof (WTree), "tree_new");
  1386.  
  1387.     init_widget (&tree->widget, y, x, lines, cols, tcallback,
  1388.          (destroy_fn) tree_destroy, (mouse_h) event_callback);
  1389.     tree->is_panel = is_panel;
  1390.     tree->selected_ptr = 0;
  1391.     tree->tree_shown = 0;
  1392.     tree->search_buffer [0] = 0;
  1393.     tree->tree_first = tree->tree_last = 0;
  1394.     tree->topdiff = tree->widget.lines / 2;
  1395.     tree->searching = 0;
  1396.     tree->done = 0;
  1397.     
  1398.     /* We do not want to keep the cursor */
  1399.     widget_want_cursor (tree->widget, 0);
  1400.     load_tree (tree);
  1401.     return tree;
  1402. }
  1403.  
  1404. static char *get_absolute_name (char *file)
  1405. {
  1406.     char dir [MC_MAXPATHLEN];
  1407.  
  1408.     if (file [0] == PATH_SEP)
  1409.     return strdup (file);
  1410.     mc_get_current_wd (dir, MC_MAXPATHLEN);
  1411.     return get_full_name (dir, file);
  1412. }
  1413.  
  1414. static int my_mkdir_rec (char *s, mode_t mode)
  1415. {
  1416.     char *p, *q;
  1417.     int result;
  1418.     
  1419.     if (!mc_mkdir (s, mode))
  1420.         return 0;
  1421.  
  1422.     /* FIXME: should check instead if s is at the root of that filesystem */
  1423.     if (!vfs_file_is_local (s))
  1424.     return -1;
  1425.     if (!strcmp (vfs_path(s), PATH_SEP_STR))
  1426.         return ENOTDIR;
  1427.     if (s [strlen (s) - 1] != PATH_SEP)
  1428.         p = copy_strings (s, PATH_SEP_STR "..", NULL);
  1429.     else
  1430.         p = copy_strings (s, "..", NULL);
  1431.     q = vfs_canon (p);
  1432.     free (p);
  1433.     if (!(result = my_mkdir_rec (q, mode))) {
  1434.         result = mc_mkdir (s, mode); 
  1435.     } 
  1436.     free (q);
  1437.     return result;
  1438. }
  1439.  
  1440. int my_mkdir (char *s, mode_t mode)
  1441. {
  1442.     int result;
  1443. #if FIXME    
  1444.     WTree *tree = 0;
  1445. #endif    
  1446.  
  1447.     result = mc_mkdir (s, mode);
  1448.     if (result) {
  1449.         char *p = vfs_canon (s);
  1450.         
  1451.         result = my_mkdir_rec (p, mode);
  1452.         free (p);
  1453.     }
  1454.     if (result == 0){
  1455.     s = get_absolute_name (s);
  1456. #if FIXME
  1457.     /* FIXME: Should receive a Wtree! */
  1458.  
  1459.     tree_add_entry (tree, s);
  1460. #endif
  1461.     free (s);
  1462.     }
  1463.     return result;
  1464. }
  1465.  
  1466. int my_rmdir (char *s)
  1467. {
  1468.     int result;
  1469. #if FIXME    
  1470.     WTree *tree = 0;
  1471. #endif    
  1472.  
  1473.     /* FIXME: Should receive a Wtree! */
  1474.     result = mc_rmdir (s);
  1475.     if (result == 0){
  1476.     s = get_absolute_name (s);
  1477. #if FIXME
  1478.     tree_remove_entry (tree, s);
  1479. #endif
  1480.     free (s);
  1481.     }
  1482.     return result;
  1483. }
  1484.  
  1485.  
  1486.